//
// Module.h
// Usage: Kernel module (*.ko) object
// CreateDate: 2009-04-09
// Author: MaJiuyue
//
//========================================
// Temp map first 1M to process's first 1M for usr print
//
#include <SCI.h>
#include "Module.h"
#include "ElfParser.h"

Module::Module(const char * strModuleName, addr_t ModuleAddress, size_t ModuleSize)
	: m_ModuleName(strModuleName),
	  m_ModuleAddress(ModuleAddress),
	  m_ModuleSize(ModuleSize)
{
}

Module::~Module()
{
}

Process * Module::CreateProcess()
{
	// Call core.ProcessManager resource to create a child process of pid0
	Resource * res = ResourceManager.RequestResource(
		ServiceCallInterface::ProcessManager::ResourceName
	);
	Process * proc = (Process *)res->CallSCI(
		ServiceCallInterface::ProcessManager::SCIID_CreateProcessKNL,
		0
	);
	if(proc == NULL)
		return NULL;

	// Request core.PageFrameAllocator
	res = ResourceManager.RequestResource(
		ServiceCallInterface::PageFrameAllocator::ResourceName
	);

	// Read module's data to process
	Context * context = proc->GetContext();
	ElfParser elf((char *)m_ModuleAddress);
	elf.SegmentFirst();
	while(elf.SegmentNext())
	{
		addr_t offset = elf.GetOffset();
		addr_t vaddr = elf.GetVaddr();
		int memsz = elf.GetMemSize();
		int filesz = elf.GetFileSize();
		
		while(memsz>0)
		{
			// Allocate page for segment
			addr_t page = res->CallSCI(ServiceCallInterface::PageFrameAllocator::SCIID_GetPageAddr);

			if(filesz>0)
			{
				memcpy((char *)page, (char *)offset, PAGE_SIZE);
				filesz -= PAGE_SIZE;
			}
	
			context->MapPage(vaddr, offset);

			offset += PAGE_SIZE;
			vaddr += PAGE_SIZE;
			memsz -= PAGE_SIZE;
		}
	}

	// Set process's entry point
	Thread * thread = proc->GetThread();
	thread->SetRegisterValue(REGS_EIP, elf.GetEntryAddr());

	// Set process's stack
	thread->SetRegisterValue(REGS_ESP, 0x80000000);
	addr_t stack_page = res->CallSCI(ServiceCallInterface::PageFrameAllocator::SCIID_GetPageAddr);
	context->MapPage(0x7FFFF000, stack_page);
/*
	// Set process's root&working directory
	res = ResourceManager.RequestResource(
		ServiceCallInterface::FileSystem::ResourceName
	);
	Directory * root = (Directory *)res->CallSCI(
		ServiceCallInterface::FileSystem::SCIID_GetRoot
	);
	proc->GetFCB()->SetRootDirectory(root);
	proc->GetFCB()->SetWorkingDirectory(root);
*/

// ============================================================
	context->MapPage(0xB8000, 0xB8000);
	context->MapPage(0xB9000, 0xB9000);
// ============================================================

	return proc;
}

